package org.example.memora.service.serviceImpl;

import lombok.extern.slf4j.Slf4j;
import org.example.memora.common.result.Result;
import org.example.memora.entity.CommentLike;
import org.example.memora.entity.CommentLikeStat;
import org.example.memora.mapper.CommentLikeMapper;
import org.example.memora.mapper.CommentLikeStatMapper;
import org.example.memora.service.CommentLikeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.stream.StreamRecords;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.time.Instant;
import java.util.*;

@Slf4j
@Service
public class CommentLikeServiceImpl implements CommentLikeService {

    // 定义阈值：当 Redis 中记录数达到此数量时，触发批量同步到数据库
    //private static final long MAX_WRITE_SIZE = 10L;

    @Autowired
    private CommentLikeMapper commentLikeMapper;

    @Autowired
    private CommentLikeStatMapper commentLikeStatMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 点赞操作：先写入 Redis 缓存（记录和计数），当缓存中数据不存在时，
     * 从数据库加载初始点赞数，再进行自增；达到阈值时批量同步到数据库。
     */
    @Transactional
    @Override
    public Result<?> likeComment(Long userId, String commentId) {
        String redisRecordKey = "comment:like:record:" + commentId;
        String redisCountKey  = "comment:like:count:" + commentId;

        // 1. 检查 Redis 集合中是否已存在该用户的点赞记录
        Boolean alreadyLiked = redisTemplate.opsForSet().isMember(redisRecordKey, String.valueOf(userId));
        if (alreadyLiked != null && alreadyLiked) {
            return Result.error("已点赞，不能重复点赞");
        } else {
            // 补充校验数据库（防止缓存丢失导致重复点赞）
            CommentLike exist = commentLikeMapper.selectByUserAndComment(userId, commentId);
            if (exist != null) {
                return Result.error("已点赞，不能重复点赞");
            }
        }

        // 2. 将点赞记录写入 Redis 的 Set（保证唯一性）
        redisTemplate.opsForSet().add(redisRecordKey, String.valueOf(userId));
        redisTemplate.expire(redisRecordKey, Duration.ofMinutes(30));
        // 3. 更新 Redis 中的点赞计数：先判断 key 是否存在
        Boolean countKeyExists = redisTemplate.hasKey(redisCountKey);
        if (countKeyExists != null && countKeyExists) {
            redisTemplate.opsForValue().increment(redisCountKey, 1);
        } else {
            // 如果 Redis 中不存在点赞计数，则从数据库加载初始值
            CommentLikeStat stat = commentLikeStatMapper.selectByPrimaryKey(commentId);
            int initialCount = (stat != null) ? stat.getLikeCount() : 0;
            // 将初始值存入 Redis
            redisTemplate.opsForValue().set(redisCountKey, String.valueOf(initialCount));
            // 然后再进行自增
            redisTemplate.opsForValue().increment(redisCountKey, 1);
        }

        Map<String, String> message = new HashMap<>();
        message.put("userId", userId.toString());
        message.put("commentId", commentId);
        message.put("action", "like");
        message.put("timestamp", String.valueOf(System.currentTimeMillis()));
        //redisTemplate.opsForStream().add("stream:post:like", message);
        // 写入 Stream，并设置 maxlen 自动裁剪（最多保留最近 10000 条）
        // 写入 Stream
        redisTemplate.opsForStream()
                .add(StreamRecords.mapBacked(message).withStreamKey("stream:comment:like"));

// 手动裁剪（注意：这个是非原子操作）
        redisTemplate.opsForStream().trim("stream:comment:like", 10);
        // 或 trim(..., true) 近似裁剪


        return Result.success(1, "点赞成功");
    }
    /**
     * 取消点赞操作
     */
    @Transactional
    @Override
    public Result<?> unlikeComment(Long userId, String commentId) {
        String redisRecordKey = "comment:like:record:" + commentId;
        String redisCountKey  = "comment:like:count:" + commentId;

        // 检查 Redis 集合中是否已存在该用户的点赞记录
        Boolean alreadyLiked = redisTemplate.opsForSet().isMember(redisRecordKey, String.valueOf(userId));
        if (alreadyLiked == null || !alreadyLiked) {
            // 补充校验数据库，防止缓存数据丢失
            CommentLike commentLike = commentLikeMapper.selectByUserAndComment(userId, commentId);
            if (commentLike == null) {
                return Result.error("没有点赞，不能取消点赞");
            }
        }
        // 删除数据库中的点赞记录（如果存在）
        if (commentLikeMapper.selectByUserAndComment(userId, commentId) != null) {
            commentLikeMapper.deleteLike(userId, commentId);
        }
        // 更新 Redis 中的点赞计数
        Boolean exists = redisTemplate.hasKey(redisCountKey);
        if (exists != null && exists) {
            String value = redisTemplate.opsForValue().get(redisCountKey);
            if (value != null && Integer.parseInt(value) > 0) {
                redisTemplate.opsForValue().decrement(redisCountKey, 1);
            }
        } else {
            // 如果 Redis 中不存在计数，则从数据库加载初始值到 Redis，然后进行自减
            CommentLikeStat stat = commentLikeStatMapper.selectByPrimaryKey(commentId);
            int initialCount = (stat != null) ? stat.getLikeCount() : 0;
            if(initialCount==0){
                return Result.error("点赞数已为0，不能取消点赞了，请检查逻辑是否有问题");
            }
            redisTemplate.opsForValue().set(redisCountKey, String.valueOf(initialCount));
            redisTemplate.opsForValue().decrement(redisCountKey, 1);
        }
        // 从 Redis 集合中移除该用户的点赞记录
        redisTemplate.opsForSet().remove(redisRecordKey, String.valueOf(userId));
        // 4. 将“取消点赞”事件写入 Redis Stream，交由消费者异步处理
        Map<String, String> message = new HashMap<>();
        message.put("userId", userId.toString());
        message.put("commentId", commentId);
        message.put("action", "unlike");
        message.put("timestamp", String.valueOf(System.currentTimeMillis()));
        redisTemplate.opsForStream().add("stream:comment:like", message);
        return Result.success(1,"取消点赞成功");
    }

    /**
     * 查询是否已点赞
     */
    /**
     * 查询是否已点赞：
     * 先从 Redis Set 中检查，如果没有，再补充校验数据库。
     */
    @Transactional
    @Override
    public boolean hasLiked(Long userId, String commentId) {
        String redisRecordKey = "comment:like:record:" + commentId;
        Boolean alreadyLiked = redisTemplate.opsForSet().isMember(redisRecordKey, String.valueOf(userId));
        if (alreadyLiked != null && alreadyLiked) {
            return true;
        } else {
            // 补充校验数据库
            CommentLike exist = commentLikeMapper.selectByUserAndComment(userId, commentId);
            return exist != null;
        }
    }

    /**
     * 批量将 Redis 中的点赞记录同步到数据库
     * @param commentId 评论ID
     */
    @Transactional
    @Override
    public void flushLikeRecords(String commentId) {
        String redisRecordKey = "comment:like:record:" + commentId;

        // 从 Redis 获取所有点赞记录（用户ID集合）
        Set<String> userIds = redisTemplate.opsForSet().members(redisRecordKey);
        if (userIds == null || userIds.isEmpty()) {
            return;
        }

        // 构造批量插入数据库的对象列表
        List<CommentLike> records = new ArrayList<>();
        for (String uid : userIds) {
            CommentLike record = new CommentLike();
            record.setUserId(Long.valueOf(uid));
            record.setCommentId(commentId);
            record.setCreatedAt(Instant.now());
            // 其他字段如 createdAt 可由数据库默认值或自行设置
            records.add(record);
        }

        // 批量插入数据库（假设 mapper 中提供了 batchInsert 方法）
        int insertedCount = commentLikeMapper.batchInsert(records);

        if (insertedCount > 0) {
            // 同步成功后清空对应的 Redis 集合，避免重复写入
            redisTemplate.delete(redisRecordKey);
            log.info("评论[{}]的点赞记录已同步到数据库，数量：{}", commentId, insertedCount);
        }
    }
}
